package org.mika.asm;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;

import net.sf.cglib.asm.ClassWriter;
import net.sf.cglib.asm.Constants;
import net.sf.cglib.core.ClassEmitter;
import net.sf.cglib.core.ClassGenerator;
import net.sf.cglib.core.CodeEmitter;
import net.sf.cglib.core.EmitUtils;
import net.sf.cglib.core.GeneratorStrategy;
import net.sf.cglib.core.ReflectUtils;

class BeanIteratorWorkerGenerator implements GeneratorStrategy {
	private Class<?> beanClass;
	
	public BeanIteratorWorkerGenerator(Class<?> beanClass) {
		this.beanClass = beanClass;
	}		

	@Override
	public byte[] generate(ClassGenerator generator) throws Exception {
		ClassWriter  writer  = new ClassWriter(true);
		ClassEmitter ce = new ClassEmitter(writer);
				
		ASMUtils.generateWorkerHeader(ce, beanClass);
		String fieldName = ASMUtils.generateWrapped(ce, beanClass);
		
		CodeEmitter emitter = EmitUtils.begin_method(
			ce, ReflectUtils.getMethodInfo(
				BeanWalker.class.getMethod("walk", BeanIterator.class)
			), Constants.ACC_PUBLIC
		);
		
		BeanInfo info = Introspector.getBeanInfo(beanClass);
		
		for(PropertyDescriptor d : info.getPropertyDescriptors()) {
			if(d.getReadMethod() != null) {
				emitter.load_arg(0);
				emitter.push(d.getName());
				
				emitter.load_this();
				emitter.getfield(fieldName);
				emitter.invoke(ReflectUtils.getMethodInfo( d.getReadMethod() ));
				
				ASMUtils.castToObject(emitter, d.getPropertyType());
				
				emitter.invoke(
					ReflectUtils.getMethodInfo(
						BeanIterator.class.getMethod("property", String.class, Object.class)
					)
				);
			}
		}
		
		emitter.return_value();
		emitter.end_method();
		
		ce.end_class();
		return writer.toByteArray();
	}
}
